/**
 * @license
 * Copyright 2024 The Model Explorer Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * ==============================================================================
 */

import {
  Graph,
  GraphCollection,
  GraphCollectionFromBuiltinAdapters,
} from '../components/visualizer/common/input_graph';

import {loadTfjsModel} from './tfjs';
import {ConfigEditor, ConfigEditorGroup} from './types';

/** Checks if the current page is running in internal colab. */
export const INTERNAL_COLAB =
  new URLSearchParams(window.location.search).get('internal_colab') === '1';

/** Checks if the given path is a supported internal storage path. */
export function isInternalStoragePath(path: string): boolean {
  return false;
}

/** Processes uploaded json file. */
export async function processUploadedJsonFile(
  file: File,
): Promise<GraphCollection[]> {
  return new Promise<GraphCollection[]>((resolve, reject) => {
    const fileReader = new FileReader();
    fileReader.onload = (event) => {
      // tslint:disable-next-line:no-any Allow custom types.
      const json = JSON.parse(fileReader.result as string) as any;
      const {graphCollections, error} = processJson(file.name, json);
      if (error) {
        reject(error);
      } else if (graphCollections) {
        resolve(graphCollections);
      }
    };
    fileReader.readAsText(file);
  });
}

/** Processes the given json string. */
export function processJson(
  collectionLabel: string,
  // tslint:disable-next-line:no-any Allow custom types.
  json: any,
): {graphCollections?: GraphCollection[]; error?: string} {
  if (json['modelTopology'] == null) {
    return loadGraphsJson(json, collectionLabel);
  } else {
    const graphCollection = loadTfjsModel(collectionLabel, json);
    return {graphCollections: [graphCollection]};
  }
}

/** Loads graphs json. */
export function loadGraphsJson(
  // tslint:disable-next-line:no-any JSON dataj.
  json: any,
  fileName: string,
): {graphCollections?: GraphCollection[]; error?: string} {
  // Use it directly if it is a GraphCollection.
  if (json['label'] != null && json['graphs'] != null) {
    return {graphCollections: [json as GraphCollection]};
  }
  // The json is generated by built-in adapter script.
  else if (Array.isArray(json) && json[0]['subgraphs'] != null) {
    return {
      graphCollections:
        convertGraphCollectionsFromBuiltinAdptersToGraphCollections(
          json as GraphCollectionFromBuiltinAdapters[],
          fileName,
        ),
    };
  }
  // The json is a list of graphs.
  else if (
    Array.isArray(json) &&
    (json.length === 0 ||
      (json.length > 0 && json[0]['id'] != null && json[0]['nodes'] != null))
  ) {
    return {
      graphCollections: [
        {
          label: fileName,
          graphs: json as Graph[],
        },
      ],
    };
  } else {
    return {error: 'Unsupported JSON format'};
  }
}

/**
 * Converts a list of GraphCollectionFromBuiltinAdapters to a list of
 * GraphCollection.
 */
export function convertGraphCollectionsFromBuiltinAdptersToGraphCollections(
  collections: GraphCollectionFromBuiltinAdapters[],
  fileName: string,
): GraphCollection[] {
  return collections.map((item) => {
    return {
      label: item.label === '' ? fileName : `${fileName} (${item.label})`,
      graphs: item.subgraphs,
    };
  });
}

/** Gets the api exposed by electron's preload script. */
export function getElectronApi() {
  // tslint:disable-next-line:no-any Allow arbitrary types.
  return (window as any)['meElectronApi'];
}

/** Checks if the given item is a ConfigEditorGroup. */
export function isConfigEditorGroup(
  item: ConfigEditor | ConfigEditorGroup,
): item is ConfigEditorGroup {
  return (item as ConfigEditorGroup).configEditors !== undefined;
}
